package bll

import (
	"context"
	"fmt"
	"gorm.io/gorm"
	log "ota/collector/logger"
	"ota/errors"
	"ota/event"
	"ota/utils"

	"github.com/lib/pq"

	"ota/model"
	"ota/model/entity"
	"ota/model/mapping"
	"ota/store"
	"ota/store/postgres"
	"time"
)

type upgradeStrategy struct {
	iUpgradeStrategy store.IUpgradeStrategy
}

var UpgradeStrategy = &upgradeStrategy{
	iUpgradeStrategy: postgres.UpgradeStrategy,
}

func init() {
	Register(UpgradeStrategy)
}

func (a *upgradeStrategy) init() func() {
	return func() {}
}

func (a *upgradeStrategy) onEvent(*event.Data) {}

func (a *upgradeStrategy) checkExist(ctx context.Context, name string) bool {

	// 车型名称校验
	var count int64
	postgres.GetDB(ctx).Model(&entity.UpgradeStrategy{}).Where("name = ?", name).Count(&count)
	if count > 0 {
		return true
	}

	return false
}

func (a *upgradeStrategy) check(ctx context.Context, id int64, op model.OtaUpgradeStrategyOpType) error {

	respUpgradeStrategy, err := a.iUpgradeStrategy.Find(ctx, &model.UpgradeStrategyInfoRequest{Id: id})
	if err != nil {
		log.Errorf("get upgrade strategy err: %v", err)

		if !errors.Is(err, gorm.ErrRecordNotFound) {
			return errors.InternalServerError.Error()
		}
	}
	if respUpgradeStrategy.Id == 0 {
		return errors.UpgradeStrategyNotExist.Error()
	}
	if _, data, err := UpgradePlan.iUpgradePlan.List(ctx, &model.UpgradePlanListRequest{
		Index:      1,
		Size:       1,
		StrategyId: utils.GetValuePointer(respUpgradeStrategy.Id),
	}, model.QueryOptions{
		OnlyList: true,
	}); err != nil {
		log.Errorf("get upgrade plan err: %v", err)
		return errors.InternalServerError.Error()
	} else {
		if len(data) > 0 {
			if op == model.UpgradeStrategyOpDelete {
				return fmt.Errorf("已有升级计划(%v %v)关联该策略，不允许删除", data[0].Id, data[0].Name)
			}
		}
	}

	return nil
}

// Create
func (a *upgradeStrategy) Create(ctx context.Context, in *model.UpgradeStrategyCreateRequest) error {

	if b := a.checkExist(ctx, in.Name); b {
		return fmt.Errorf("升级策略名称已存在")
	}

	var (
		err error
	)

	if err = model.OrderType(in.Order).CheckOrder(); err != nil {
		return err
	}

	c := buildUpgradeStrategy(in)
	_, err = a.iUpgradeStrategy.Create(ctx, c)
	return err
}

// Update
func (a *upgradeStrategy) Update(ctx context.Context, in *model.UpgradeStrategyUpdateRequest) error {

	if err := a.check(ctx, *in.Id, model.UpgradeStrategyOpUpdate); err != nil {
		return err
	}

	var (
		dict = make(map[string]interface{})
	)

	if in.Id != nil {
		dict["id"] = in.Id
	}

	if in.FirmwareIds != nil {
		dict["firmware_ids"] = in.FirmwareIds
	}

	if in.Name != nil {
		dict["name"] = in.Name
	}

	if in.UpgradeType != nil {
		dict["upgrade_type"] = in.UpgradeType
	}

	if in.Order != nil {
		if err := model.OrderType(in.Order).CheckOrder(); err != nil {
			return err
		}
		dict["order"] = in.Order
	}

	if in.FailureNotifyMethod != nil {
		dict["failure_notify_method"] = in.FailureNotifyMethod
	}

	if in.RetryCount != nil {
		dict["retry_count"] = in.RetryCount
	}

	if in.CreatedAt != nil {
		dict["created_at"] = in.CreatedAt
	}

	if in.UpdatedAt != nil {
		dict["updated_at"] = in.UpdatedAt
	}

	// do other update here
	updateAt := time.Now().Unix()
	in.UpdatedAt = &updateAt

	upgradeStrategyCache.Remove(*in.Id)
	return a.iUpgradeStrategy.Update(ctx, *in.Id, dict)
}

// Delete
func (a *upgradeStrategy) Delete(ctx context.Context, in *model.UpgradeStrategyDeleteRequest) error {

	if err := a.check(ctx, in.Id, model.UpgradeStrategyOpDelete); err != nil {
		return err
	}

	upgradeStrategyCache.Remove(in.Id)
	return a.iUpgradeStrategy.Delete(ctx, in.Id)
}

// List
func (a *upgradeStrategy) List(ctx context.Context, in *model.UpgradeStrategyListRequest) (*model.UpgradeStrategyListResponse, error) {
	var (
		err   error
		total int
		list  []*entity.UpgradeStrategy
		out   = &model.UpgradeStrategyListResponse{}
		opts  = model.QueryOptions{OrderFields: model.NewOrderFields(model.NewOrderField("created_at", model.OrderByDESC))}
	)

	if total, list, err = a.iUpgradeStrategy.List(ctx, in, opts); err != nil {
		return nil, err
	}

	out.Total = total
	out.List = mapping.UpgradeStrategysEntityToDto(list)

	return out, nil
}

// Find
func (a *upgradeStrategy) Find(ctx context.Context, in *model.UpgradeStrategyInfoRequest) (*model.UpgradeStrategyInfo, error) {
	var (
		err  error
		data *entity.UpgradeStrategy
		out  = &model.UpgradeStrategyInfo{}
	)

	if data, err = a.iUpgradeStrategy.Find(ctx, in); err != nil {
		return nil, err
	}

	out = mapping.UpgradeStrategyEntityToDto(data)
	return out, nil
}

// buildUpgradeStrategy build entity
func buildUpgradeStrategy(in *model.UpgradeStrategyCreateRequest) *entity.UpgradeStrategy {

	ety := &entity.UpgradeStrategy{}

	ety.Id = in.Id

	if len(in.FirmwareIds) != 0 {
		ety.FirmwareIds = in.FirmwareIds
	} else {
		ety.FirmwareIds = pq.Int64Array{}
	}

	ety.Name = in.Name

	ety.Order = in.Order

	ety.UpgradeType = in.UpgradeType

	ety.FailureNotifyMethod = in.FailureNotifyMethod

	ety.RetryCount = in.RetryCount

	ety.CreatedAt = time.Now().Unix()

	ety.UpdatedAt = in.UpdatedAt

	return ety
}
